use std::ptr::null;

fn main() {
  let s = String::from("hello");
  take_ownership(s);
  // println!("{}",s); //error[E0382]: borrow of moved value: `s`

  let x = 1;
  make_copy(x);
  println!("{}", x); //1

  let s = give_ownership();
  println!("{}", s); //hello

  /** 1. borrowing借用 ---> 就是引用*/
  // 之前说过
  let mut s1 = String::from("abc");
  s1 = take_and_give_ownership(s1/*现在传的是pointer指针, 不是传的&s1引用, 即不是借用*/); //这里s1借给 take_and_give_ownership 这个函数用了, 不还回来的话, s1是不能用的
  //↑ 必须要重新接受下 才能收回所有权
  println!("{}", s1); //abc
  // 有没有什么办法简化上面的操作？
  // ---> 引用

  /** 2.1 & ---> 引用, 创建一个指向值的引用*/
  //  + 但是并不会拥有它, So在引用离开作用域后也不会被丢弃(比如这里的s1的引用传给calculate_length,但calculate_length运行完后,s1仍然可用)
  let mut s1 = String::from("Hello");
  let len = calculate_length(&s1);
  println!("after calculate_length ---> s1 = {}", s1); //Hello
  // let p1 = &s1;
  // let len = calculate_length(p1);
  println!("len: {}", len); //5

  /** 2.2 &mut ---> 可变引用*/
  //如果你先改变引用指向的值, 需要使用 &mut 可变引用, 并且需要变量本身也是一个可变变量 ---> let mut
  modify_s(&mut s1);
  println!("after modify_s ---> s1: {}", s1); //modify_s after---> s1: Hello, world!

  /** 2.3 引用规则 */
  /** 同一时间内至多只能有一个可变引用
      error[E0499]: cannot borrow `z` as mutable more than once at a time*/
  // 主要是防止数据竞争, 比如多线程时
  let mut z = String::from("hhhh!");
  // ↓ is √
  /*let z1_ref = &z;
  let z2_ref = &z;
  println!("{}", z1_ref); //hhhh!
  println!("{}", z2_ref); //hhhh!*/

  // ↓ is not ok
  let z3_ref = &mut z;
  let z4_ref = &mut z;
  //↓ 同时打印两个时, 第一个 println!("{}", z3_ref) 就会报错 ( 但注释掉第一个打印就不会报错
  // println!("{}", z3_ref); //error[E0499]: cannot borrow `z` as mutable more than once at a time
  // println!("{}", z4_ref);
/*
error[E0499]: cannot borrow `z` as mutable more than once at a time
  --> 04.2.references-and-borrowing\src\main.rs:43:16
   |
42 |   let z3_ref = &mut z;
   |                ------ first mutable borrow occurs here
43 |   let z4_ref = &mut z;
   |                ^^^^^^ second mutable borrow occurs here
44 |   println!("{}", z3_ref); //error[E0499]: cannot borrow `z` as mutable more than once at a time
   |                  ------ first borrow later used here
*/

  /** 并且当一个可变引用后, 之前的不可变引用就不能用了
      error[E0502]: cannot borrow `v` as mutable because it is also borrowed as immutable*/
  /*let mut v = vec![1, 2, 3, 4, 5];
  let first = &v[0];
  v.push(6);
  println!("The first element is: {}", first);*/
  /* https://kaisery.github.io/trpl-zh-cn/ch08-01-vectors.html#%E8%AF%BB%E5%8F%96-vector-%E7%9A%84%E5%85%83%E7%B4%A0
    error[E0502]: cannot borrow `v` as mutable because it is also borrowed as immutable
  --> 08.common-collections\src\bin\Vec.rs:35:3
   |
34 |   let first = &v[0];
   |                - immutable borrow occurs here
35 |   v.push(6);
   |   ^^^^^^^^^ mutable borrow occurs here
36 |   println!("The first element is: {}", first);
   |                                        ----- immutable borrow later used here


    为什么第一个元素的引用会关心 vector 结尾的变化？不能这么做的原因是由于 vector 的工作方式：在 vector 的结尾增加新元素时，在没有足够空间将所有所有元素依次相邻存放的情况下，可能会要求分配新内存并将老的元素拷贝到新的空间中。这时，第一个元素的引用就指向了被释放的内存。借用规则阻止程序陷入这种状况。
  */
}

fn take_ownership(some_string:String){
  println!("{}", some_string);
}

fn make_copy(i:i32){
  println!("i = {}", i);
}

fn give_ownership() -> String{
  let s = String::from("hello");
  s
}

fn take_and_give_ownership(s: String)->String{
  s
}

fn calculate_length(s: &String) -> usize/*i32*//*todo 为嘛这里用size自适应类型?*/{
  // return s.len() as i32; //也 √
  s.len()
}

fn modify_s(s: &mut String){
  s.push_str(", world!");
}
